﻿#ifndef SRC_UTIL_FUNCTION_TRAITS_H_
#define SRC_UTIL_FUNCTION_TRAITS_H_

#include <tuple>
#include <functional>

namespace toolkit {

template<typename T>
struct FunctionTraits;

// 普通函数
template<typename Ret, typename... Args>
struct FunctionTraits<Ret(Args...)>
{
public:
    enum { arity = sizeof...(Args) };
    typedef Ret functionType(Args...);
    typedef Ret returnType;
    using stlFunctionType = std::function<functionType>;
    typedef Ret(*pointer)(Args...);

    template<size_t I>
    struct args
    {
        static_assert(I < arity, "索引超出范围，索引必须小于参数数量");
        using type = typename std::tuple_element<I, std::tuple<Args...> >::type;
    };
};

// 函数指针
template<typename Ret, typename... Args>
struct FunctionTraits<Ret(*)(Args...)> : FunctionTraits<Ret(Args...)>{};

// std::function
template <typename Ret, typename... Args>
struct FunctionTraits<std::function<Ret(Args...)>> : FunctionTraits<Ret(Args...)>{};

// 成员函数
#define FUNCTION_TRAITS(...) \
    template <typename ReturnType, typename ClassType, typename... Args>\
    struct FunctionTraits<ReturnType(ClassType::*)(Args...) __VA_ARGS__> : FunctionTraits<ReturnType(Args...)>{}; \

FUNCTION_TRAITS()
FUNCTION_TRAITS(const)
FUNCTION_TRAITS(volatile)
FUNCTION_TRAITS(const volatile)

// 函数对象
template<typename Callable>
struct FunctionTraits : FunctionTraits<decltype(&Callable::operator())>{};

} /* namespace toolkit */

#endif /* SRC_UTIL_FUNCTION_TRAITS_H_ */
